package com.huang.store.core;

import java.io.InputStream;
import java.util.concurrent.TimeUnit;

import org.springframework.web.multipart.MultipartFile;

import com.huang.store.bean.OssFile;
import com.huang.store.config.OssProperties;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import io.minio.BucketExistsArgs;
import io.minio.GetPresignedObjectUrlArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.UploadObjectArgs;
import io.minio.http.Method;

/**
 * minio 基础模板
 *
 * @author han
 * @since 2022-04-19 14:23:42
 */
public class MinioTemplate {

    private final MinioClient minioClient;
    private final OssProperties ossProperties;

    public MinioTemplate(MinioClient minioClient, OssProperties ossProperties) {
        this.minioClient = minioClient;
        this.ossProperties = ossProperties;
    }

    /**
     * 获取图片地址
     *
     * @param bucketName        令牌桶
     * @param fileName          文件名称
     * @return                  图片地址
     */
    public String getUrl(String bucketName, String fileName) throws Exception {
        return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                .method(Method.GET)
                .bucket(bucketName)
                .object(fileName)
                .expiry(2, TimeUnit.HOURS)
                .build());
    }

    /**
     * 上传文件
     *
     * @param bucketName        桶令牌
     * @param objectName        文件名称
     * @param fileInputStream   文件地址
     * @return oss访问地址
     */
    public OssFile upload(String bucketName, String objectName, MultipartFile fileInputStream) throws Exception {

        if (StrUtil.isBlank(bucketName)) {
            throw new IllegalArgumentException("bucketName 不能为空");
        }
        if (StrUtil.isBlank(objectName)) {
            throw new IllegalArgumentException("文件信息不能为空");
        }
        if (fileInputStream.isEmpty()) {
            throw new IllegalArgumentException("上传文件不能为空");
        }

        String suffixName = objectName.substring(objectName.lastIndexOf("."));
        objectName = IdUtil.getSnowflakeNextId() + suffixName;
        InputStream is = fileInputStream.getInputStream();

        existsOrCreateBucketName(bucketName);
        minioClient.putObject(PutObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .stream(is, is.available(), -1)
                .build());

        return new OssFile(objectName, bucketName);
    }

    /**
     * 上传文件
     *
     * @param bucketName 桶令牌
     * @param objectName 文件名称
     * @param fileName   文件地址
     * @return oss访问地址
     */
    private OssFile upload(String bucketName, String objectName, String fileName) throws Exception {

        if (StrUtil.isBlank(bucketName)) {
            throw new IllegalArgumentException("bucketName 不能为空");
        }
        objectName = validateUpload(objectName, fileName);
        existsOrCreateBucketName(bucketName);
        minioClient.uploadObject(UploadObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .filename(fileName)
                .build());
        return new OssFile(objectName, bucketName);
    }

    /**
     * 上传文件
     *
     * @param objectName 文件名称
     * @param fileName   文件地址
     * @return oss访问地址
     */
    private OssFile upload(String objectName, String fileName) throws Exception {
        objectName = validateUpload(objectName, fileName);
        return uploadObject(objectName, fileName);
    }

    /**
     * 校验上传文件参数
     *
     * @param objectName    文件名称
     * @param fileName      本地文件地址
     */
    private String validateUpload(String objectName, String fileName) {
        if (StrUtil.isBlank(objectName)) {
            throw new IllegalArgumentException("文件名称不能为空");
        }
        if (StrUtil.isBlank(fileName)) {
            throw new IllegalArgumentException("文件不能为空");
        }
        String suffixName = objectName.substring(objectName.lastIndexOf("."));
        objectName = IdUtil.getSnowflakeNextId() + suffixName;
        return objectName;
    }

    /**
     * 上传文件
     *
     * @param fileName   文件地址
     * @return oss访问地址
     */
    private OssFile upload(String fileName) throws Exception {
        if (StrUtil.isBlank(fileName)) {
            throw new IllegalArgumentException("文件不能为空");
        }
        String objectName = IdUtil.fastSimpleUUID() + fileName.substring(fileName.lastIndexOf("."));
        return uploadObject(objectName, fileName);
    }

    private boolean makeBucketName(String bucketName) {
        try {
            minioClient.makeBucket(MakeBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
            return Boolean.TRUE;
        } catch (Exception e) {
            e.printStackTrace();
            return Boolean.FALSE;
        }

    }

    private boolean existsBucketName(String bucketName) {
        try {
            return minioClient.bucketExists(BucketExistsArgs.builder()
                    .bucket(bucketName)
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
            return Boolean.FALSE;
        }

    }

    private void existsOrCreateBucketName(String bucketName) throws IllegalAccessException {
        if (!existsBucketName(bucketName)) {
            if (!makeBucketName(bucketName)) {
                throw new IllegalAccessException("令牌桶创建失败！");
            }
        }
    }

    private OssFile uploadObject(String objectName, String fileName) throws Exception {
        String bucketName = ossProperties.getBucketName();
        existsOrCreateBucketName(bucketName);

        minioClient.uploadObject(UploadObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .filename(fileName)
                .build());
        return new OssFile(objectName, bucketName);
    }

}
